//
// Created on 2025/7/19.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef STREAMCORE_ASYNC_WORKER_H
#define STREAMCORE_ASYNC_WORKER_H
#include <functional>
#include <napi/native_api.h>

class AsyncWorker {
public:
    using ExecuteFunc = std::function<void(napi_env, void *)>;
    using OnOkFunc = std::function<napi_value(napi_env, void *)>;
    using OnFailFunc = std::function<napi_value(napi_env, void *)>;
    using Deleter = void (*)(void *);

    AsyncWorker(const char *work_name = "default_async_work") : name_(work_name), data_(nullptr, nullptr) {}

    void set_execute(ExecuteFunc func) { execute_func_ = std::move(func); }
    void set_ok(OnOkFunc func) { ok_func_ = std::move(func); }
    void set_fail(OnFailFunc func) { fail_func_ = std::move(func); }

    void set_data(void *data, Deleter deleter) { data_ = std::unique_ptr<void, Deleter>(data, deleter); }

    napi_value Create(napi_env env) {
        napi_value promise;
        napi_value resource_name;

        // 创建异步工作
        napi_status status = napi_create_string_utf8(env, name_, NAPI_AUTO_LENGTH, &resource_name);
        if (status != napi_ok) {
            napi_throw_error(env, nullptr, "Failed to create resource name");
            return nullptr;
        }

        status = napi_create_async_work(env, nullptr, resource_name, ExecuteWrapper, CompleteWrapper, this, &work_);
        if (status != napi_ok) {
            napi_throw_error(env, nullptr, "Failed to create async work");
            return nullptr;
        }

        status = napi_create_promise(env, &deferred_, &promise);
        if (status != napi_ok) {
            napi_throw_error(env, nullptr, "Failed to create promise");
            return nullptr;
        }

        status = napi_queue_async_work(env, work_);
        if (status != napi_ok) {
            napi_throw_error(env, nullptr, "Failed to queue async work");
            return nullptr;
        }

        return promise;
    }

    template <typename T> static std::unique_ptr<AsyncWorker> New(const char *name, T **out_data) {
        auto worker = std::make_unique<AsyncWorker>(name);
        auto *raw_data = new T();
        *out_data = raw_data;
        worker->data_.reset(raw_data, [](void *ptr) { delete static_cast<T *>(ptr); });
        return worker;
    }


private:
    static napi_value GetUndefined(napi_env env) {
        napi_value result;
        napi_get_undefined(env, &result);
        return result;
    }

    static void ExecuteWrapper(napi_env env, void *data) {
        auto *worker = static_cast<AsyncWorker *>(data);
        try {
            if (worker->execute_func_) {
                worker->execute_func_(env, worker->data_.get());
            }
            worker->status_ = napi_ok;
        } catch (const std::exception &e) {
            worker->e_ = e;
            worker->status_ = napi_generic_failure;
        }
    }

    static void CompleteWrapper(napi_env env, napi_status status, void *data) {
        auto *worker = static_cast<AsyncWorker *>(data);
        napi_value result;

        try {
            if (status == napi_ok && worker->status_ == napi_ok) {
                result = worker->ok_func_ ? worker->ok_func_(env, worker->data_.get()) : GetUndefined(env);
                napi_resolve_deferred(env, worker->deferred_, result);
            } else {
                throw worker->e_;
            }
        } catch (const std::exception &e) {
            napi_create_string_utf8(env, e.what(), NAPI_AUTO_LENGTH, &result);
            napi_reject_deferred(env, worker->deferred_, result);
        }


        napi_delete_async_work(env, worker->work_);
        delete worker;
    }

private:
    napi_deferred deferred_;
    napi_async_work work_;
    const char *name_;

    ExecuteFunc execute_func_;
    OnOkFunc ok_func_;
    OnFailFunc fail_func_;
    std::unique_ptr<void, Deleter> data_;
    std::exception e_;
    napi_status status_;
};

#endif // STREAMCORE_ASYNC_WORKER_H
